home *** CD-ROM | disk | FTP | other *** search
- // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
- // see COPYRIGHT for reuse legalities
- //
-
- #import "RIBCommandList.h"
- #import "RIBCommand.h"
-
- #import "WW3DShape.h"
- #import "WWSceneClock.h"
- #import "WW3DAttributeState.h"
- #import "usefulWW3DFunctions.h"
-
- @implementation RIBCommandList
-
- - init
- {
- [super init];
- eveCode = NULL;
- dirtyBoundingBox = TRUE;
-
- return self;
-
- }
-
- - awake
- {
- [super awake];
-
- eveCode = NULL;
- dirtyBoundingBox = TRUE;
-
- return self;
- }
-
- - free
- {
- //NXLogError("RIBCommandList %d being free'ed\n", self);
- //NXLogError("RIBCommandList: freeing %p", self);
- [self freeObjects];
- if (eveCode)
- { free(eveCode);
- }
- return [super free];
- }
-
- // override all list insertion and deletion routines to mark myself dirty
- - addObject:anObject { dirtyBoundingBox = TRUE; return [super addObject:anObject]; }
- - insertObject:anObject at:(unsigned)index { dirtyBoundingBox = TRUE; return [super insertObject:anObject at:(unsigned)index]; }
- - removeObjectAt:(unsigned)index { dirtyBoundingBox = TRUE; return [super removeObjectAt:(unsigned)index]; }
- - removeLastObject { dirtyBoundingBox = TRUE; return [super removeLastObject]; }
- - replaceObjectAt:(unsigned)index with:newObject { dirtyBoundingBox = TRUE; return [super replaceObjectAt:(unsigned)index with:newObject]; }
- - appendList: (List *)otherList { dirtyBoundingBox = TRUE; return [super appendList: (List *)otherList]; }
- - addObjectIfAbsent:anObject { dirtyBoundingBox = TRUE; return [super addObjectIfAbsent:anObject]; }
- - removeObject:anObject { dirtyBoundingBox = TRUE; return [super removeObject:anObject]; }
- - replaceObject:anObject with:newObject { dirtyBoundingBox = TRUE; return [super replaceObject:anObject with:newObject]; }
- - empty { dirtyBoundingBox = TRUE; return [super empty]; }
-
- - (const char *)eveCode { return eveCode; }
- - setEveCode:(char *)newEveCode
- {
- if (eveCode)
- { free(eveCode);
- }
- if (newEveCode)
- { eveCode = NXCopyStringBuffer(newEveCode);
- }
- else
- { eveCode = NULL;
- }
- return self;
- }
-
- - _setEveCode:(char *)newEveCode
- {
- if (newEveCode)
- { eveCode = NXCopyStringBuffer(newEveCode);
- }
- else
- { eveCode = NULL;
- }
- return self;
- }
-
- - setEveCodeArgc:(int)argc argv:(char **)argv
- {
- int i, howMany = 1;
- char *tmpEveCode, *ptr;
-
-
- for (i = 0; i < argc; i++)
- { howMany += 3 + strlen(argv[i]);
- }
- ptr = tmpEveCode = (char *)calloc(howMany, 1);
-
- sprintf(ptr, "%s ", argv[0]);
- ptr += strlen(argv[0]) + 1;
-
- for (i = 1; i < argc; i++)
- { sprintf(ptr, "{%s} ", argv[i]);
- ptr += strlen(argv[i]) + 3;
- }
-
- [self setEveCode:tmpEveCode];
-
- free(tmpEveCode);
-
- return self;
- }
-
- // okay, usually "copy" doesn't actually do a deep copy.
- // but, in the case of this subclass, we're gonna.
- - copyFromZone:(NXZone *)zone
- {
- id newCopy = [super copyFromZone:zone];
- int i, howMany = [self count];
-
-
- [newCopy _setEveCode:eveCode];
- for (i = 0; i < howMany; i++)
- { [newCopy replaceObjectAt:i with:[[self objectAt:i] copyFromZone:zone]];
- }
- return newCopy;
- }
-
-
- // need to walk down my RIBCommands, asking each one...
- - (BOOL)hasBoundingBox
- {
- int howMany, i = 0;
- BOOL found = NO;
-
-
- howMany = [self count];
- while (!found && (i < howMany))
- { if ([[self objectAt:i] hasBoundingBox])
- { found = YES;
- }
- i++;
- }
- return found;
- }
-
- - (BOOL)isLerpable { return YES; }
-
- // need to walk down my RIBCommands, asking each one...
- - (BOOL)pushesCTM
- {
- int howMany, i = 0;
- int pushes = 0,
- pops = 0;
-
-
- howMany = [self count];
- for (i = 0; i < howMany; i++)
- { if ([[self objectAt:i] pushesCTM])
- { pushes++;
- }
- if ([[self objectAt:i] popsCTM])
- { pops++;
- }
- }
- if (pushes > pops)
- { return YES;
- }
- return NO;
- }
-
- - (BOOL)popsCTM
- {
- int howMany, i = 0;
- int pushes = 0,
- pops = 0;
-
-
- howMany = [self count];
- for (i = 0; i < howMany; i++)
- { if ([[self objectAt:i] pushesCTM])
- { pushes++;
- }
- if ([[self objectAt:i] popsCTM])
- { pops++;
- }
- }
- if (pops > pushes)
- { return YES;
- }
- return NO;
- }
-
- - (BOOL)pushesOrPopsCTM
- {
- int howMany, i = 0;
- int pushes = 0,
- pops = 0;
-
-
- howMany = [self count];
- for (i = 0; i < howMany; i++)
- { if ([[self objectAt:i] pushesCTM])
- { pushes++;
- }
- if ([[self objectAt:i] popsCTM])
- { pops++;
- }
- }
- if (pushes != pops)
- { return YES;
- }
- return NO;
- }
-
- - (float)lastSampleIsAt { return 0.0; }
-
-
- - (unsigned long int)maxSampleBandwidth
- {
- unsigned long int maxSampleBandwidth = 50; //WAVE FIX ME
- int i, howMany = [self count];
-
-
- for (i = 0; i < howMany; i++)
- { maxSampleBandwidth += [(id <WWRenderable>)[self objectAt:i] maxSampleBandwidth];
- }
-
- return maxSampleBandwidth;
- }
-
-
- // need to walk down my RIBCommands, asking each one...
- - (BOOL)isMotionBlurrable
- {
- int howMany, i = 0;
- BOOL found = NO;
-
-
- howMany = [self count];
- while (!found && (i < howMany))
- { if ([[self objectAt:i] isMotionBlurrable])
- { found = YES;
- }
- i++;
- }
- return found;
- }
-
- - (BOOL)isCompoundCommand { return YES; }
-
-
- // need to walk down my RIBCommands, asking each one...
- // no, unfortunately, it's not as easy as that.
- // This is actually much more like a WW3DShape.
- // we might have transformative commands inside the list.
- // what if we had a RIBScale and a RIBSphere object?
- // we need to keep a notion of a CTM inside the list, and
- // apply it to both the bounding box thus far and the current
- // command
- // NOTE: the changes haven't been made yet...
-
- - (int)findBoundingBoxFromRIBCommands:(int)startingIndex using:attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtBound tmpBoundingBox;
- RtMatrix tmpCTM;
- int i = startingIndex,
- incr,
- howMany = [self count];
- id cmd;
- id newAttributeState;
-
-
- // first we need to find a bounding box to start with
- while (i < howMany)
- { cmd = [self objectAt:i];
-
- // if the cmd pops the attribute stack, we're done.
- // we return how many commands we've gone through in our time here
- if ([cmd popsCTM])
- { i++;
- return (i - startingIndex);
- }
-
- if ([cmd pushesCTM]) // here we go again...
- { newAttributeState = [[WW3DAttributeState alloc] init];
- i++;
- incr = [self findBoundingBoxFromRIBCommands:i using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- // we now need to merge this sub-attribute block into our current one
- if ([newAttributeState hasBoundingBox])
- { // This means that the bounding box in newAttributeState needs to be
- // transformed by the ctm of attributeState, and then we need to
- // "grow" to the current bound with that tranformed sub-bound.
-
- [attributeState getTransformMatrix:tmpCTM];
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, [newAttributeState boundingBox], tmpCTM);
- [attributeState growBoundingBox:&tmpBoundingBox];
- }
- else
- { NXLogError("warning: RIBCommandList <%s> has a moot set of commands at indices %d to %d\n", [myShape shapeName], (i - 1), (i + incr - 1));
- NXLogError("\tif there was a LightSource or AreaLight source in there, you can ignore this warning, though...\n");
- }
- i += incr;
- }
- else
- { [cmd transformCTM:attributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- i++;
- }
-
- if ([cmd hasBoundingBox])
- { // great! we grow the bound of the current attribute state
- [attributeState growBoundingBox:[cmd boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]];
- }
-
- }
- return (i - startingIndex);
- }
-
-
-
- - calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i;
- id newAttributeState;
-
-
- if (![self hasBoundingBox])
- { return self; // I don't have a bounding box!
- }
-
- // I have a bounding box; but I'm not sure what to set it to
- // initially... I'll use the bounding box of the first
- // RIBCommand I have that has a bounding box.
- newAttributeState = [[WW3DAttributeState alloc] init];
- i = [self findBoundingBoxFromRIBCommands:0 using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- if (i != [self count])
- { NXLogError("warning: RIBCommandList in shape <%s> has an unbalanced attribute delimiter at command %d (expected %d)\n",
- [myShape shapeName], i, [self count]);
- return nil;
- }
-
- if ([newAttributeState hasBoundingBox])
- { N3D_CopyBound(*([newAttributeState boundingBox]), boundingBox);
- }
- else
- { NXLogError("warning: RIBCommandList in shape <%s> thought it had a bounding box, but it seems it doesn't...\n",
- [myShape shapeName]);
- return nil;
- }
- return self;
- }
-
-
- - setBoundingBox:(RtBound *)newBoundingBox
- {
- N3D_CopyBound(*newBoundingBox, boundingBox);
-
- return self;
- }
-
- - (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStartTime endingAt:(RtFloat)intervalEndTime
- {
- if (dirtyBoundingBox)
- { [self calculateBoundingBoxStartingAt:intervalStartTime endingAt:intervalEndTime];
- }
- return &boundingBox;
- }
-
- - setMyShape:shape
- {
- int howMany = [self count],
- i = 0;
-
-
- myShape = shape;
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] setMyShape:myShape];
- }
- return self;
- }
-
- - shape { return myShape; }
-
- - (unsigned long int)dataBandwidth
- {
- int howMany = [self count],
- i = 0;
- unsigned
- long int dataBandwidth = 0;
-
-
- for (i = 0; i < howMany; i++)
- { dataBandwidth += [(id <WWRenderable>)[self objectAt:i] dataBandwidth];
- }
-
- return dataBandwidth;
- }
-
-
- // note: because we've made the WWSampleList "safe" for having
- // multiple samples with the same data, it's perfectly valid to return
- // yourself or b
- - lerpWith:b by:(float)uValue
- {
- id newMe = nil, newElement;
- int i, howMany = [self count];
-
-
- if (([self class] != [b class]) || (uValue <= 0.0) || (howMany != [b count]))
- { return self;
- }
-
- if (uValue >= 1.0)
- { return b;
- }
-
- newMe = [self copyFromZone:[self zone]];
- [newMe empty];
-
- for (i = 0; i < howMany; i++)
- { newElement = [[self objectAt:i] copyFromZone:[self zone]];
- if ([newElement isLerpable])
- { [newElement lerpSelfWith:[b objectAt:i] by:uValue];
- }
- [newMe insertObject:newElement at:i];
- }
-
- return newMe;
- }
-
- - lerpSelfWith:b by:(float)uValue
- {
- id element;
- int i, howMany = [self count];
-
-
- if (([self class] != [b class]) || (uValue <= 0.0) || (howMany != [b count]))
- { return self;
- }
-
- if (uValue >= 1.0)
- { return b;
- }
-
- for (i = 0; i < howMany; i++)
- { element = [self objectAt:i];
- [element lerpSelfWith:[b objectAt:i] by:uValue];
- }
-
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
- {
- int howMany = [self count],
- i = 0;
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
-
- return self;
- }
-
- - renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
- {
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- return [self renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int howMany = [self count],
- i = 0;
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- return self;
- }
-
- - renderMaps:(WW3DCamera *)camera
- {
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- return [self renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- - renderSelfAsBox:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int howMany = [self count],
- i = 0;
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] renderSelfAsBox:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- return self;
- }
-
- - renderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int howMany = [self count],
- i = 0;
- id <WWRenderable> obj;
-
-
- if (NXDrawingStatus == NX_DRAWING)
- { for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- }
- else
- { for (i = 0; i < howMany; i++) // do the moot check
- { obj = (id <WWRenderable>)[self objectAt:i];
- if (![obj isMoot])
- { [obj renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- }
- }
-
- return self;
- }
-
- - renderSelf:(WW3DCamera *)camera
- {
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- - preRenderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- return [self preRenderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- - preRenderSelf:(WW3DCamera *)camera
- {
- return [self renderSelf:camera];
- }
-
-
- - (int)spinThroughSubAttributeBlocks:(int)startingIndex
- {
- int i = startingIndex,
- howMany = [self count];
- id cmd;
-
-
- while (i < howMany)
- { cmd = [self objectAt:i];
-
- // if the cmd pops the attribute stack, we're done.
- // we return how many commands we've gone through in our time here
- if ([cmd popsCTM])
- { i++;
- return (i - startingIndex);
- }
-
- if ([cmd pushesCTM]) // here we go again...
- { i++;
- i += [self spinThroughSubAttributeBlocks:i];
- }
- else
- { i++;
- }
- }
- return (i - startingIndex);
- }
-
- - transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int howMany = [self count],
- i = 0;
- id cmd;
-
-
- while (i < howMany)
- { cmd = [self objectAt:i];
- if ([cmd pushesCTM])
- { //okay, recursively spin until we pop or finish...
- i++;
- i += [self spinThroughSubAttributeBlocks:0];
- }
- else
- { [(id <WWRenderable>)[self objectAt:i++] transformCTM:attributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- }
-
- return self;
-
- }
-
- // WavesWorld archiving:
- // writeEve:(NXStream *)stream
- // writeScene:(NXStream *)stream
-
- - oldWriteEve:(NXStream *)stream atTabLevel:(int)tab
- {
- int howMany = [self count],
- i;
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] writeEve:stream atTabLevel:tab];
- }
- return self;
- }
-
- - writeEve:(NXStream *)stream atTabLevel:(int)tab
- {
- int i;
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- if (!eveCode)
- { NXPrintf(stream, "# this RIBCommandList had no eveCode...");
- }
- else
- { NXPrintf(stream, "%s", eveCode);
- }
-
- return self;
- }
-
- - writeScene:(NXStream *)stream atTabLevel:(int)tab
- {
- return [self writeEve:stream atTabLevel:tab];
- }
-
- - write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
- {
- int howMany = [self count],
- i;
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[self objectAt:i] write3DTextScene:stream atTabLevel:tab index:index++ time:time until:lastTime];
- // really need to be moving the X coordinate by the X bound of each, and make it cumulative...
- }
- return self;
- }
-
- - writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
- {
- int howMany = [self count],
- i, newTab = tab + 1;
- id <WWRenderable> aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "# RIBCommandList:\n");
- for (i = 0; i < (howMany-1); i++)
- { aCmd = [self objectAt:i];
- if (![aCmd isMootStartingAt:currentTime endingAt:currentTime])
- { if ([aCmd popsCTM])
- { newTab--;
- }
- [aCmd writeInventorAtTime:currentTime to:stream atTabLevel:newTab];
- if ([aCmd pushesCTM])
- { newTab++;
- }
- NXPrintf(stream, "\n");
- }
- }
-
- aCmd = [self objectAt:i];
- if (![aCmd isMootStartingAt:currentTime endingAt:currentTime])
- { [(id <WWRenderable>)[self objectAt:i] writeInventorAtTime:currentTime to:stream atTabLevel:newTab];
- }
- return self;
- }
-
- - (BOOL)theSameAs:otherRIBCommand
- {
- // make the default NO...
- return NO;
- }
-
- - (BOOL)similarTo:otherRIBCommand
- {
- if ([self class] != [otherRIBCommand class])
- { return NO;
- }
- return YES;
- }
-
-
- - (BOOL)isMoot
- {
- int i, howMany = [self count];
-
-
- for (i = 0; i < howMany; i++)
- { if (![(id <WWRenderable>)[self objectAt:i] isMoot])
- { return NO;
- }
- }
- // if there are no commands, or they're all moot, then so am i...
- return YES;
- }
-
- - (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime { return [self isMoot]; }
-
- // boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- - class { return [super class]; }
-
- @end
-